home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / MBUF.C < prev    next >
Text File  |  1993-11-23  |  8KB  |  396 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "config.h"
  6. #include "mbuf.h"
  7. #include "proc.h"
  8.  
  9. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  10.  * if any
  11.  */
  12. struct mbuf *
  13. free_p(struct mbuf *bp)
  14. {
  15.     struct mbuf *abp = bp->anext;
  16.  
  17.     if(bp == NULLBUF) {
  18.         return NULLBUF;
  19.     }
  20.     while(bp != NULLBUF) {
  21.         bp = free_mbuf(bp);
  22.     }
  23.     return abp;
  24. }
  25.  
  26. /* Free entire queue of packets (of mbufs) */
  27. void
  28. free_q(struct mbuf **q)
  29. {
  30.     struct mbuf *bp;
  31.  
  32.     while((bp = dequeue(q)) != NULLBUF) {
  33.         free_p(bp);
  34.     }
  35. }
  36.  
  37. /* Count up the total number of bytes in a packet */
  38. int16
  39. len_p(struct mbuf *bp)
  40. {
  41.     int16 cnt = 0;
  42.  
  43.     while(bp != NULLBUF) {
  44.         cnt += bp->cnt;
  45.         bp = bp->next;
  46.     }
  47.     return cnt;
  48. }
  49.  
  50. /* Count up the number of packets in a queue */
  51. int16
  52. len_q(struct mbuf *bp)
  53. {
  54.     int16 cnt = 0;
  55.  
  56.     for( ; bp != NULLBUF; cnt++, bp = bp->anext) ;
  57.  
  58.     return cnt;
  59. }
  60.  
  61. /* Trim mbuf to specified length by lopping off end */
  62. void
  63. trim_mbuf(struct mbuf **bpp,int16 length)
  64. {
  65.     int16 tot = 0;
  66.     struct mbuf *bp;
  67.  
  68.     if(bpp == NULLBUFP || *bpp == NULLBUF) {
  69.         /* Nothing to trim */
  70.         return;
  71.     }
  72.     if(length == 0) {
  73.         /* Toss the whole thing */
  74.         free_p(*bpp);
  75.         *bpp = NULLBUF;
  76.         return;
  77.     }
  78.     /* Find the point at which to trim. If length is greater than
  79.      * the packet, we'll just fall through without doing anything
  80.      */
  81.     for(bp = *bpp; bp != NULLBUF; bp = bp->next) {
  82.         if(tot + bp->cnt < length) {
  83.             tot += bp->cnt;
  84.         } else {
  85.             /* Cut here */
  86.             bp->cnt = length - tot;
  87.             free_p(bp->next);
  88.             bp->next = NULLBUF;
  89.             break;
  90.         }
  91.     }
  92. }
  93.  
  94. /* Duplicate/enqueue/dequeue operations based on mbufs */
  95.  
  96. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  97.  * This is done without copying data; only the headers are duplicated,
  98.  * but without data segments of their own. The pointers are set up to
  99.  * share the data segments of the original copy. The return pointer is
  100.  * passed back through the first argument, and the return value is the
  101.  * number of bytes actually duplicated.
  102.  */
  103. int16
  104. dup_p(struct mbuf **hp,struct mbuf *bp,int16 offset,int16 cnt)
  105. {
  106.     struct mbuf *cp;
  107.     int16 tot = 0;
  108.  
  109.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP) {
  110.         if(hp != NULLBUFP) {
  111.             *hp = NULLBUF;
  112.         }
  113.         return 0;
  114.     }
  115.     *hp = cp = alloc_mbuf(0);
  116.  
  117.     /* Skip over leading mbufs that are smaller than the offset */
  118.     while(bp != NULLBUF && bp->cnt <= offset) {
  119.         offset -= bp->cnt;
  120.         bp = bp->next;
  121.     }
  122.     if(bp == NULLBUF) {
  123.         free_mbuf(cp);
  124.         *hp = NULLBUF;
  125.         return 0;       /* Offset was too big */
  126.     }
  127.     for(;;) {
  128.         /* Make sure we get the original, "real" buffer
  129.          * (i.e. handle the case of duping a dupe)
  130.          */
  131.         if(bp->dup != NULLBUF) {
  132.             cp->dup = bp->dup;
  133.         } else {
  134.             cp->dup = bp;
  135.         }
  136.         /* Increment the duplicated buffer's reference count */
  137.         cp->dup->refcnt++;
  138.         cp->data = bp->data + offset;
  139.         cp->cnt = min(cnt,bp->cnt - offset);
  140.         offset = 0;
  141.         cnt -= cp->cnt;
  142.         tot += cp->cnt;
  143.         bp = bp->next;
  144.  
  145.         if(cnt == 0 || bp == NULLBUF) {
  146.             break;
  147.         }
  148.         cp = cp->next = alloc_mbuf(0);
  149.     }
  150.     return tot;
  151. }
  152.  
  153. #if defined NETROM || defined PACKET
  154. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  155. struct mbuf *
  156. copy_p(struct mbuf *bp,int16 cnt)
  157. {
  158.     struct mbuf *cp;
  159.     char *wp;
  160.  
  161.     if(bp == NULLBUF || cnt == 0) {
  162.         return NULLBUF;
  163.     }
  164.     cp = alloc_mbuf(cnt);
  165.     wp = cp->data;
  166.  
  167.     while(cnt != 0 && bp != NULLBUF) {
  168.         int16 n = min(cnt,bp->cnt);
  169.         memcpy(wp,bp->data,n);
  170.         wp += n;
  171.         cp->cnt += n;
  172.         cnt -= n;
  173.         bp = bp->next;
  174.     }
  175.     return cp;
  176. }
  177. #endif
  178.  
  179. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  180.  * bytes actually pulled off
  181.  */
  182. int16
  183. pullup(struct mbuf **bph,char *buf,int16 cnt)
  184. {
  185.     int16 tot = 0;
  186.  
  187.     if(bph != NULLBUFP) {
  188.         struct mbuf *bp;
  189.  
  190.         while(cnt > 0 && (bp = *bph) != NULLBUF) {
  191.             int16 n = min(cnt,bp->cnt);
  192.  
  193.             if(buf != NULLCHAR) {
  194.                 if(n == 1) {                    /* Common case optimization */
  195.                     *buf = *bp->data;
  196.                 } else if(n > 1) {
  197.                     memcpy(buf,bp->data,n);
  198.                 }
  199.                 buf += n;
  200.             }
  201.             tot += n;
  202.             cnt -= n;
  203.             bp->data += n;
  204.             bp->cnt -= n;
  205.  
  206.             if(bp->cnt <= 0) {
  207.                 /* If this is the last mbuf of a packet but there
  208.                  * are others on the queue, return a pointer to
  209.                  * the next on the queue. This allows pullups to
  210.                  * to work on a packet queue
  211.                  */
  212.                 if(bp->next == NULLBUF && bp->anext != NULLBUF) {
  213.                     *bph = bp->anext;
  214.                     free_mbuf(bp);
  215.                 } else {
  216.                     *bph = free_mbuf(bp);
  217.                 }
  218.             }
  219.         }
  220.     }
  221.     return tot;
  222. }
  223.  
  224. /* Append mbuf to end of mbuf chain */
  225. void
  226. append(struct mbuf **bph,struct mbuf *bp)
  227. {
  228.     if(bph == NULLBUFP || bp == NULLBUF) {
  229.         return;
  230.     }
  231.     if(*bph == NULLBUF) {
  232.         /* First one on chain */
  233.         *bph = bp;
  234.     } else {
  235.         struct mbuf *p = *bph;
  236.  
  237.         for( ; p->next != NULLBUF ; p = p->next) ;
  238.         p->next = bp;
  239.     }
  240. }
  241.  
  242. /* Insert specified amount of contiguous new space at the beginning of an
  243.  * mbuf chain. If enough space is available in the first mbuf, no new space
  244.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  245.  * tacked on the front of the chain.
  246.  *
  247.  * This operation is the logical inverse of pullup(), hence the name.
  248.  */
  249. struct mbuf *
  250. pushdown(struct mbuf *bp,int16 size)
  251. {
  252.     /* Check that bp is real, that it hasn't been duplicated, and
  253.      * that it itself isn't a duplicate before checking to see if
  254.      * there's enough space at its front.
  255.      */
  256.     if(bp != NULLBUF
  257.       && bp->refcnt == 1
  258.       && bp->dup == NULLBUF
  259.       && (bp->data - (char *)(bp + 1)) >= size) {
  260.         /* No need to alloc new mbuf, just adjust this one */
  261.         bp->data -= size;
  262.         bp->cnt += size;
  263.     } else {
  264.         struct mbuf *nbp = alloc_mbuf(size);
  265.         nbp->next = bp;
  266.         nbp->cnt = size;
  267.         bp = nbp;
  268.     }
  269.     return bp;
  270. }
  271.  
  272. /* Append packet to end of packet queue */
  273. void
  274. enqueue(struct mbuf **q,struct mbuf *bp)
  275. {
  276.     int i_state;
  277.  
  278.     if(q == NULLBUFP || bp == NULLBUF) {
  279.         return;
  280.     }
  281.     i_state = dirps();
  282.  
  283.     if(*q == NULLBUF) {
  284.         /* List is empty, stick at front */
  285.         *q = bp;
  286.     } else {
  287.         struct mbuf *p = *q;
  288.  
  289.         for( ; p->anext != NULLBUF ; p = p->anext) ;
  290.         p->anext = bp;
  291.     }
  292.     restore(i_state);
  293.     psignal(q,1);
  294. }
  295.  
  296. /* Unlink a packet from the head of the queue */
  297. struct mbuf *
  298. dequeue(struct mbuf **q)
  299. {
  300.     struct mbuf *bp;
  301.     int i_state;
  302.  
  303.     if(q == NULLBUFP) {
  304.         return NULLBUF;
  305.     }
  306.     i_state = dirps();
  307.  
  308.     if((bp = *q) != NULLBUF) {
  309.         *q = bp->anext;
  310.         bp->anext = NULLBUF;
  311.     }
  312.     restore(i_state);
  313.     return bp;
  314. }
  315.  
  316. /* Copy user data into an mbuf */
  317. struct mbuf *
  318. qdata(char *data,int16 cnt)
  319. {
  320.     struct mbuf *bp = alloc_mbuf(cnt);
  321.  
  322.     memcpy(bp->data,data,cnt);
  323.     bp->cnt = cnt;
  324.     return bp;
  325. }
  326.  
  327. #ifdef VANESSA
  328. /* Copy mbuf data into user buffer */
  329. int16
  330. dqdata(struct mbuf *bp,char *buf,unsigned cnt)
  331. {
  332.     int16 tot = 0;
  333.  
  334.     if(buf != NULLCHAR) {
  335.         struct mbuf *bp1;
  336.  
  337.         for(bp1 = bp; bp1 != NULLBUF; bp1 = bp1->next) {
  338.             int16 n = min(bp1->cnt,cnt);
  339.             memcpy(buf,bp1->data,n);
  340.             cnt -= n;
  341.             buf += n;
  342.             tot += n;
  343.         }
  344.         free_p(bp);
  345.     }
  346.     return tot;
  347. }
  348. #endif
  349.  
  350. /* Pull a 32-bit integer in host order from buffer in network byte order.
  351.  * On error, return 0. Note that this is indistinguishable from a normal
  352.  * return.
  353.  */
  354. int32
  355. pull32(struct mbuf **bpp)
  356. {
  357.     char buf[4];
  358.  
  359.     if(pullup(bpp,buf,4) != 4) {
  360.         /* Return zero if insufficient buffer */
  361.         return 0;
  362.     }
  363.     return get32(buf);
  364. }
  365.  
  366. /* Pull a 16-bit integer in host order from buffer in network byte order.
  367.  * Return -1 on error
  368.  */
  369. int16
  370. pull16(struct mbuf **bpp)
  371. {
  372.     char buf[2];
  373.  
  374.     if(pullup(bpp,buf,2) != 2){
  375.         /* Return -1 if insufficient buffer */
  376.         return -1;
  377.     }
  378.     return get16(buf);
  379. }
  380.  
  381. /* Pull single character from mbuf
  382.  * Return -1 on error
  383.  */
  384. int
  385. pullchar(struct mbuf **bpp)
  386. {
  387.     char c;
  388.  
  389.     if(pullup(bpp,&c,1) != 1) {
  390.         /* Return -1 if insufficient buffer */
  391.         return -1;
  392.     }
  393.     return c;
  394. }
  395.  
  396.